package net.helix.ui.panels.library;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.JComponent;
import javax.swing.TransferHandler;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.TreePath;

import net.helix.engine.library.LibraryTreeNode;
import net.helix.ui.panels.view.ViewPane;

import org.jdesktop.swingx.JXTreeTable;

public class LibraryTreeTransferHandler extends TransferHandler {
	private static final long serialVersionUID = 1L;
	public LibraryTreeTableModel model;
	public LibraryTreeTransferHandler(LibraryTreeTableModel model){
		super();
		this.model = model;
	}
	//protected TreePath dragPath;
	protected TreePath[] dragPaths;
	//protected LibraryTreeNode draggedNode;
	protected LibraryTreeNode[] draggedNodes;
	protected Transferable createTransferable(JComponent c) {
		System.out.println("createTransferable");
		
		Transferable t = null;
		if(c instanceof JXTreeTable) {
			JXTreeTable treeTable = (JXTreeTable) c;
			
			//t = new GenericTransferable(treeTable.getPathForRow(treeTable.getSelectedRow()));
			
			int[] rows = treeTable.getSelectedRows();
			
			draggedNodes = new LibraryTreeNode[rows.length];
			dragPaths = new TreePath[rows.length];
			
			for(int i=0;i<rows.length;i++){
				dragPaths[i] = treeTable.getPathForRow(rows[i]);
				if(dragPaths[i] != null){
					draggedNodes[i] = (LibraryTreeNode) dragPaths[i].getLastPathComponent();
				}else{
					draggedNodes[i] = null;
				}
				
			}
			
			t = new LibraryPathArrayTransferable(draggedNodes);
			/*
			dragPath = treeTable.getPathForRow(treeTable.getSelectedRow());
			if (dragPath != null) {
				draggedNode = (LibraryTreeNode) dragPath.getLastPathComponent();
			}
			*/
		}
		
	    return t;
	}
	public int getNumberOfDraggedNodes(){
		if(draggedNodes != null){
			return draggedNodes.length;
		}else{
			return -1;
		}
	}
	
	protected void exportDone(JComponent source, Transferable data, int action) {
	    System.out.println("exportDone, source=" + source.getClass().getName() + ", action="+action);
	    
	    
	    if(source instanceof JXTreeTable) {
	    	System.out.println("model.isMouseOver = "+model.isMouseOver);
	    	
	    	if(model.isMouseOver == true && model.useFilter == false){
	    		// can't drag around items when in search mode
	    		
		    	JXTreeTable treeTable = (JXTreeTable) source;
		    	LibraryTreeTableModel model = (LibraryTreeTableModel) treeTable.getTreeTableModel();
		    	TreePath currentPath = treeTable.getPathForRow(treeTable.getSelectedRow());
		    	
		    	//LibraryPathArrayTransferable gTransfer = (LibraryPathArrayTransferable) data;
		    	
		    	LibraryTreeNode[] nodes = null;
		    	try {
		    		nodes = (LibraryTreeNode[]) data.getTransferData(LibraryPathArrayTransferable.LibraryTreeNodeFlavor);
		    		
		    		for(int i=0;i<nodes.length;i++){
		    			if(nodes[i] != null){
				    		if(currentPath != null){
				    			addNodes(currentPath, model, nodes[i].getPathTo());
				    		}else{
				    			insertNodes(treeTable, model, nodes[i].getPathTo());
				    		}
		    			}
			    	}
		    		
		    		
		    	} catch (UnsupportedFlavorException e) {
		    		e.printStackTrace();
		    	} catch (IOException e) {
		    		e.printStackTrace();
		    	}
	    		
	    	}
	    	
	    		
	    		
			
	    	
	    	
	    }
	    if(source instanceof ViewPane) {
	    	System.out.println("Detected as dropping to a view!");
	    	
	    	
	    }
	    
	    
	    draggedNodes = null;
	    super.exportDone(source, data, action);
	    
	}
	
	protected void addNodes(TreePath currentPath, LibraryTreeTableModel model, TreePath dataPath) {
		LibraryTreeNode targetNode = (LibraryTreeNode) currentPath.getLastPathComponent();
		
		TreePath movePath = dataPath;
		LibraryTreeNode moveNode = (LibraryTreeNode) movePath.getLastPathComponent();
		if(!moveNode.equals(targetNode)) {
			if(model.canMoveNodeTo(moveNode, targetNode, targetNode.getChildCount())){	
				model.removeNodeFromParent(moveNode);
				model.insertNodeInto(moveNode, targetNode, targetNode.getChildCount());
			}
		}
	}
	protected void insertNodes(JXTreeTable treeTable, LibraryTreeTableModel model, TreePath dataPath) {
		Point location = ((LibraryTreeDropTarget) treeTable.getDropTarget()).getMostRecentDragLocation();
		TreePath path = treeTable.getPathForLocation(location.x, location.y);
		LibraryTreeNode targetNode = (LibraryTreeNode) path.getLastPathComponent();
		LibraryTreeNode parent = (LibraryTreeNode)(targetNode).getParent();
		
		TreePath movedPath = dataPath;
		LibraryTreeNode moveNode = (LibraryTreeNode) movedPath.getLastPathComponent();
		if(!moveNode.equals(targetNode)) {
			if(model.canMoveNodeTo(moveNode, parent, model.getIndexOfChild(parent, targetNode))){
				model.removeNodeFromParent(moveNode);
				model.insertNodeInto(moveNode, parent, model.getIndexOfChild(parent, targetNode));
			}
		}
		
	}
	public int getSourceActions(JComponent c) {
		return TransferHandler.MOVE;
	}
	public BufferedImage getDragImage(JXTreeTable tree, int index) {
		BufferedImage image = null;
		try {
			if (dragPaths != null) {
				int row = tree.getRowForPath(dragPaths[index]);
				// TODO: fix flickering for multiple item dragging
				Rectangle pathBounds = tree.getCellRect(row, 0, false);
				TableCellRenderer r = tree.getCellRenderer(row, 0);
				JComponent lbl = (JComponent)r.getTableCellRendererComponent(tree, draggedNodes[index].toString(), false, false, row, 0);
				lbl.setBounds(pathBounds);
				image = new BufferedImage((int)pathBounds.getWidth(), (int)pathBounds.getHeight(), java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE);
				Graphics2D graphics = image.createGraphics();
				graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
				lbl.setOpaque(false);
				lbl.paint(graphics);
				graphics.dispose();
			}
		}catch (RuntimeException re) {

		}
		return image;
	}
}
